package fr.umlv.ig.model;

import java.util.LinkedList;
import java.util.List;

import fr.umlv.ig.event.LineDataEvent;
import fr.umlv.ig.event.LineDataItineraryEvent;
import fr.umlv.ig.event.LineDataStationEvent;
import fr.umlv.ig.event.MetroDataLineEvent;
import fr.umlv.ig.event.StationEvent;
import fr.umlv.ig.listener.LineListener;
import fr.umlv.ig.listener.MetroListener;
import fr.umlv.ig.listener.StationListener;
import fr.umlv.ig.listener.TrainListener;

public abstract class AbstractMetroModel implements MetroModel {
	
	protected boolean firingLineListener = false;
	protected boolean firingStationListener = false;
	protected boolean firingTrainListener = false;
	protected boolean firingMetroListener = false;
	
	private final List<LineListener> lineListeners = new LinkedList<LineListener>();
	private final List<StationListener> stationListeners = new LinkedList<StationListener>();
	private final List<TrainListener> trainListeners = new LinkedList<TrainListener>();
	private final List<MetroListener> metroListeners = new LinkedList<MetroListener>();
	
	public void addLineListener(LineListener listener) {
		lineListeners.add(listener);
		
	}
	
	
	public void removeLineListener(LineListener listener) {
		if(firingLineListener) {
			throw new IllegalStateException("Cannot remove listeners while fire... is using them");
		}
		lineListeners.remove(listener);
	}
	
	
	public void addStationListener(StationListener listener) {

		stationListeners.add(listener);
		
	}
	
	
	public void removeStationListener(StationListener listener) {
		if(firingStationListener) {
			throw new IllegalStateException("Cannot remove listeners while fire... is using them");
		}
		stationListeners.remove(listener);
	}
	
	
	public void addTrainListener(TrainListener listener) {
		trainListeners.add(listener);
	}
	
	
	public void removeTrainListener(TrainListener listener) {
		if(firingTrainListener) {
			throw new IllegalStateException("Cannot remove listeners while fire... is using them");
		}
		trainListeners.remove(listener);
	}
	
	
	public void addMetroListener(MetroListener listener) {
		metroListeners.add(listener);
	}
	
	
	public void removeMetroListener(MetroListener listener) {
		if(firingMetroListener) {
			throw new IllegalStateException("Cannot remove listeners while fire... is using them");
		}
		metroListeners.remove(listener);
	}
	
	
	protected void fireStationOpened(Station station) {
		fireStationChanged(new StationEvent(station, StationEvent.STATION_OPENED));		
	}
	
	
	protected void fireStationClosed(Station station) {
		fireStationChanged(new StationEvent(station, StationEvent.STATION_CLOSED));
	}
	
	
	protected void fireStationChanged(StationEvent event) {
		try {
			firingStationListener =true;
			for(StationListener l : stationListeners) {
				l.stationChange(event);
			}
		}
		finally {
			firingStationListener = false;
		}
	}
	
	
	protected void fireIntervalStationAdded(Line line, int index0, int index1) {
		LineDataStationEvent event = new LineDataStationEvent(line,
				LineDataEvent.INTERVAL_STATION_ADDED , index0, index1);
		try {
			firingStationListener = true;
			for(LineListener l : lineListeners) {
				l.intervalStationAdded(event);
			}
		}
		finally {
			firingLineListener = false;
		}
	}
	
	
	protected void fireIntervalItineraryAdded(Line line, int index0, int index1) {
		LineDataItineraryEvent event = new LineDataItineraryEvent(line, 
				LineDataEvent.INTERVAL_ITINERARY_ADDED,index0, index1);
		try {
			firingStationListener = true;
			for(LineListener l : lineListeners) {
				l.intervalItineraryAdded(event);
			}
		}
		finally {
			firingLineListener = false;
		}
	}
	
	
	protected void fireLineAdded(Line line) {
		MetroDataLineEvent event = new MetroDataLineEvent(this, MetroDataLineEvent.INTERVAL_ADDED);
		try {
			firingMetroListener = true;
			for(MetroListener l : metroListeners) {
				l.lineChange(event);
			}	
		}
		finally {
			firingMetroListener = true;
		}
	}
	
	
}
